小Y的地铁
Time Limit: 50 Sec Memory Limit: 256 MB
Description
Output
对于每组输入数据,输出一行一个整数,表示除掉这 n 个换乘站之外,最少有几个换乘站。
4
4
1 2 1 2
8
1 2 3 4 1 2 3 4
5
5 4 3 3 5
8
1 2 3 4 1 3 2 4
Sample Output
0
0
0
1
HINT
n <= 44
Solution
首先,答案显然只和几个区域的连通状态有关,那么我们可以写出四种本质不同的方案。(即下图中被线分开的六块)。
我们可以考虑,对于一条线,其他线(显然仅有 部分相交 与 完全相交 两种)造成的贡献。打出表来,上图是不会造成交点的线段种类。
既然知道了这个,我们的复杂度显然可以做到 O(4 ^ (n / 2))。还是不足以通过,怎么办呢?
模拟退火大法好!
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
| #include<bits/stdc++.h> using namespace std; typedef long long s64;
const int ONE = 105; const int INF = 2147483640;
int get() { int res = 1, Q = 1; char c; while( (c = getchar()) < 48 || c > 57) if(c == '-') Q = -1; if(Q) res = c - 48; while( (c = getchar()) >= 48 && c <= 57) res = res * 10 + c - 48; return res * Q; }
int n, num; int pos[ONE], val[ONE]; int vis[ONE], a[ONE]; int Ans = INF; struct power {int l, r;} A[ONE];
int x[ONE][ONE], y[ONE][ONE];
void Deal_first() { x[1][2] = x[1][4] = x[1][5] = 1; x[2][1] = x[2][3] = x[2][6] = 1; x[3][1] = x[3][3] = x[3][6] = 1; x[4][2] = x[4][4] = x[4][5] = 1; for(int i = 1; i <= 4; i++) y[i][1] = y[i][2] = 1; }
int Now;
int Judge(int pos, int type) { int res = Now; for(int i = pos, j = pos + 1; j <= num; j++) { if(A[i].r < A[j].l) continue; if(A[i].r < A[j].r) res -= !x[a[i]][a[j]]; if(A[j].r < A[i].r) res -= !y[a[i]][a[j]]; } for(int i = 1, j = pos; i < pos; i++) { if(A[i].r < A[j].l) continue; if(A[i].r < A[j].r) res -= !x[a[i]][a[j]]; if(A[j].r < A[i].r) res -= !y[a[i]][a[j]]; }
a[pos] = type;
for(int i = pos, j = pos + 1; j <= num; j++) { if(A[i].r < A[j].l) continue; if(A[i].r < A[j].r) res += !x[a[i]][a[j]]; if(A[j].r < A[i].r) res += !y[a[i]][a[j]]; } for(int i = 1, j = pos; i < pos; i++) { if(A[i].r < A[j].l) continue; if(A[i].r < A[j].r) res += !x[a[i]][a[j]]; if(A[j].r < A[i].r) res += !y[a[i]][a[j]]; }
Now = res, Ans = min(Ans, res); return res; }
double Random() {return (double)rand() / RAND_MAX;} void SA() { if(num == 0) return; double T = num * 2; while(T >= 0.01) { int pos = rand() % num + 1, type = rand() % 4 + 1; int ori = Now, ori_type = a[pos];
int dE = Judge(pos, type) - ori; if(dE <= 0 || Random() <= exp(-dE / T)) a[pos] = type; else Judge(pos, ori_type);
T *= 0.9993; } }
void Deal() { Ans = INF; n = get(); for(int i = 1; i <= n; i++) a[i] = get(), pos[a[i]] = vis[a[i]] = 0; for(int i = n; i >= 1; i--) if(!pos[a[i]]) pos[a[i]] = i;
num = 0; for(int i = 1; i <= n; i++) if(!vis[a[i]] && pos[a[i]] != i) A[++num] = (power){i, pos[a[i]]}, vis[a[i]] = 1;
for(int i = 1; i <= num; i++) a[i] = rand() % 4 + 1; Ans = 0; for(int i = 1; i <= num; i++) for(int j = i + 1; j <= num; j++) { if(A[i].r < A[j].l) break; if(A[i].r < A[j].r) Ans += !x[a[i]][a[j]]; if(A[j].r < A[i].r) Ans += !y[a[i]][a[j]]; } Now = Ans; for(int i = 1; i <= 10; i++) SA(); printf("%d\n", Ans); }
int main() { Deal_first(); int T = get(); while(T--) Deal(); }
|